package com.itheima.dao;

import com.itheima.entity.Emp;
import org.apache.ibatis.annotations.*;

import java.util.Date;
import java.util.List;


/**
 * 用于演示使用Mybatis执行sql语句的基本操作
 */
@Mapper
public interface EmpMapper_使用Mybatis执行SQL语句 {
    /*查询全部数据*/
    @Select("select * from emp")
    public List<Emp> selectAll();

    /*删除数据*/
    @Delete("delete from emp where id = #{abc}")
    //如果mapper接口方法形参只有一个普通类型的参数，#{…}占位符里面的属性名可以随便写，如：#{id}、#{value}、#{abc} ... 。
    public void delete(Integer id); //调用delete方法时会自动将id赋值给#{abc}

    /*根据主键查找数据*/
    @Select("select * from emp where id = #{value}")
    public Emp selectByPrimaryKey(Integer id);

    /*传多个参数*/
    @Select("select * from emp where username=#{username} and password=#{password}")
    public Emp selectByUsernameAndPassword(String username, String password);
/**  ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓*/
//    老版本的Mybatis会报错,并不知道#{username}对应形参中的username,#{password}对应形参中的password,需要写成:
    /*select * from emp where username=#{param1} and password=#{param2}*/
//    或者 使用注解给形参中的username和password起别名,#{...}中写别名,来告诉Mybatis参数对应规则,写成:
    /*@Select("select * from emp where username=#{abc} and password=#{"password"}")
    public Emp selectByUsernameAndPassword(@Param("abc") String username,@Param("password") String password);*/
//    所以如果是低版本的Mybatis,则不能使用参数名作为SQL中的参数占位符的名称


    /*
     * 预编译SQL
     * 1.性能更高(减少语句相同部分的编译次数,直接填入数据即可)
     * 2.更安全(防止SQL注入攻击: SQL注入是通过操作输入的数据来修改事先定义好的SQL语句，以达到执行代码对服务器进行攻击或者获取非法数据的攻击手段)
     *
     * 数据库执行SQL语句过程: SQL语法解析检查 -> 优化SQL -> 编译SQL -> 执行SQL
     */

    /**
     * 参数占位符
     * <p>
     * #{…}
     * 执行SQL时，会将#{…}替换为?，生成预编译SQL，会自动设置参数值。
     * 使用时机：参数传递，都使用#{…}
     * <p>
     * ${…}
     * 拼接SQL。直接将参数拼接在SQL语句中，存在SQL注入问题。
     * 使用时机：如果对表名、列表进行动态设置时使用。
     * <p>
     * 预编译#{...}占位符会把内容直接当做值赋给表中字段,字符串类型会自动在两边加引号,而非预编译${...}只是单纯地将内容拼到SQL语句中,当内容是字符串时不会左右加引号,需要手动在SQL中S{...}两边加单/双引号
     * <p>
     * 通过使用预编译SQL,解决了SQL注入安全问题
     */

    @Options(useGeneratedKeys = true, keyProperty = "id")
//在插入数据时会将数据库表中自增字段id自动生成的值赋给Service层调用此insert方法时传递的emp对象中的成员变量id,从而在Service层中可以获得自动生成的id字段
    @Insert("INSERT INTO learnsql.emp(username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time) VALUES (#{username}, #{password},  #{name},  #{gender},  #{image},  #{job},  #{entrydate},  #{deptId},  #{createTime},  #{updateTime})")
    public void insert(Emp emp);//插入一行时,形参给实体类对象,insertSQL语句中#{...}占位符处直接使用成员变量名即可自动给占位符赋值


    @Update("update learnsql.emp set username=#{username}, password=#{password}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
//与添加的区别是,添加不需要id,而修改需要id来定位某条数据,而这个id是由@Options(useGeneratedKeys = true, keyProperty = "id")在添加时自动返回给emp对象的
    void update(Emp emp);


    /*
    实体类属性名 和 数据库表查询返回的字段名一致，mybatis会自动封装。
    如果实体类属性名 和 数据库表查询返回的字段名不一致，不能自动封装。

    3种方式解决:
    1.起别名：在SQL语句中，对不一样的列名起别名，别名和实体类属性名一样。
    2.手动结果映射：通过 @Results及@Result 进行手动结果映射。
    3.开启驼峰命名：如果字段名与属性名符合驼峰命名规则，mybatis会自动通过驼峰命名规则映射。(A_COLUMN_ABC -> aColumnAbc)
    配置文件application.properties中添加
    #开启驼峰命名自动映射，即从数据库字段名 a_column 映射到Java 属性名 aColumn。mybatis.configuration.map-underscore-to-camel-case=true
     */

    /*方式一:起别名*/
    @Select("select username, password, name, gender, image, job, entrydate, dept_id as deptId, create_time as createTime, update_time as updateTime from learnsql.emp where id = #{id_随便叫什么}")
    Emp selectByPrimaryKey_1(Integer id);

    /*方式二:手动结果映射 @Results声明结果集 @Result声明某一字段列的映射关系*/
    @Results(id = "empResult", value = { //id = 结果集名称(随便起)方便其他方法重复调用,value = {@Result,@Result,@Result,...}真正的结果集映射关系
            @Result(column = "dept_id", property = "deptId"),//column = 数据库中的字段列名(如果SQL查询时为这一字段指定了别名,则column应该写别名),property = 实体类成员变量名
            @Result(column = "create_time", property = "createTime"),
            @Result(column = "update_time", property = "updateTime")
//            @Result(column = "id",property = "id",id = true)//id=true表示告知Mybatis这一字段是主键,方便在扩展框架中使用
    })//该结果集映射只对下面紧跟的方法生效
    @Select("select id,username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp")
    List<Emp> selectAll_1();

    @ResultMap("empResult")//其他方法需要用之前定义过的结果集映射关系时,可以用@ResultMap("结果集名称")注解来调用
    @Select("select * from emp where name = #{name随表叫什么}")
    Emp selectByName(String name);

    //条件查询:形参赋值给查询条件
//    @ResultMap("empResult")
//    @Select("select *" +
//            " from emp" +
//            " where name like concat(\"%\",#{cname},\"%\") and gender = #{gender} and entrydate between #{begin} and #{end}" +
//            " order by update_time desc")
    List<Emp> selectByCondition(String name, Short gender, Date begin, Date end);

    List<Emp> selectByCondition_1(String name, Short gender, Date begin, Date end);

    void update2(Emp emp);


    List<Emp> selectByIds(List<Integer> ids);//形参是集合,返回值也是集合

}